package tools

import java.io.{File, FileInputStream}
import java.nio.file.Files

import config.{Global, MyAwait, MyFile}
import dao.GrnaDao
import models.Tables.GrnaRow
import org.apache.commons.io.{FileUtils, IOUtils}
import play.api.data.Form
import play.api.data.FormBinding.Implicits._
import play.api.data.Forms._
import play.api.libs.json.{JsObject, Json}
import play.api.mvc.{AnyContent, Request}
import play.shaded.oauth.org.apache.commons.codec.binary.Base64
import utils.{ExecCommand, PdfToImage}

import scala.jdk.CollectionConverters._

object GoKegg extends MyFile with MyAwait {

  case class GoKeggData(method: String, species: String, id: String)

  val GoKeggForm: Form[GoKeggData] = Form(
    mapping(
      "method" -> text,
      "species" -> text,
      "id" -> text
    )(GoKeggData.apply)(GoKeggData.unapply)
  )

  def goOrKegg(grnaDao: GrnaDao)(implicit request: Request[AnyContent]): JsObject = {
    var valid = "true"
    var msg = ""
    var img1 = ""
    var img2 = ""
    val f = disTmp(Global.random)
    val tmpDir = s"${Global.path}/tmp/$f"
    val row = GrnaRow(f, System.currentTimeMillis().toString, 0)
    grnaDao.insert(row).toAwait

    var table: Seq[Map[String, String]] = Seq()
    try {

      val tools = s"${Global.path}/tools/enrich"
      val enrich = s"${Global.path}/enrich"
      val data = GoKeggForm.bindFromRequest.get
      val abbr = data.method

      val geneIdFile = s"$tmpDir/GeneID.txt"
      val geneid = "Geneid" +: data.id.split(",").map(_.trim)
      FileUtils.writeLines(geneIdFile.toFile, geneid.toBuffer.asJava)

      val cmds = if (abbr == "kegg") {
        Array(s"perl $tools/kegg/kegg_enrich.pl $tmpDir $enrich/${data.species}.kegg.xls")
      } else {
        Array(s"perl $tools/go/go_enrich.pl $tmpDir $enrich/${data.species}.go.xls")
      }

      val execCommand = new ExecCommand
      execCommand.exect(cmds, tmpDir)
      cmds.foreach(println)
      if (execCommand.isSuccess) {
        val (i1, i2, t) = if (abbr == "kegg") {
          PdfToImage.pdf2Png(s"Ko.enrich", tmpDir)
          PdfToImage.pdf2Png(s"ko_dodge", tmpDir)
          (s"$tmpDir/Ko.enrich.png", s"$tmpDir/ko_dodge.png", s"$tmpDir/Ko.Ko.enrich.xls")
        } else {
          PdfToImage.pdf2Png(s"go.Go.enrich", tmpDir)
          PdfToImage.pdf2Png(s"go_stack", tmpDir)
          (s"$tmpDir/go.Go.enrich.png", s"$tmpDir/go_stack.png", s"$tmpDir/go.Go.enrich.xls")
        }

        if (t.readLines.length == 1) {
          valid = "false"
          msg = "No Results!"
          tmpDir.delete
        } else {
          img1 = getBase64Str(i1.toFile)
          img2 = getBase64Str(i2.toFile)
          table = t.readLines.tail.map(_.split("\t").zipWithIndex.map(x => x._2.toString -> x._1).toMap).toSeq
        }
      } else {
        valid = "false"
        msg = "No Results!"
      }
   //   tmpDir.delete
    } catch {
      case e: Exception => valid = "false"; msg = e.getMessage
    }

    Json.obj("valid" -> valid, "msg" -> msg, "img1" -> img1, "img2" -> img2, "table" -> table,"f" -> f)

  }

  def disTmp(tmpDir: String): String = {
    if (s"${Global.path}/tmp/$tmpDir".toFile.exists) {
      disTmp(Global.random)
    } else {
      tmpDir
    }
  }

  def getBase64Str(imageFile: File): String = {
    val inputStream = new FileInputStream(imageFile)
    val bytes = IOUtils.toByteArray(inputStream)
    val bytes64 = Base64.encodeBase64(bytes)
    inputStream.close()
    new String(bytes64)
  }

}
